/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.common.serialization.kryo.optimization;

import com.aduib.boot.common.serialization.api.ObjectReader;
import com.aduib.boot.common.serialization.api.SerializationClean;
import com.aduib.boot.common.serialization.kryo.utils.KryoUtils;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.io.Input;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;

/**
 * @description: KryoObjectReader
 * @author: zzh
 * @date: 2021/10/12 10:29
 */
public class KryoObjectReader implements ObjectReader, SerializationClean {

    private Kryo kryo;

    private Input input;

    public KryoObjectReader(InputStream inputStream) {
        this.input= KryoUtils.getInput();
        input.setInputStream(inputStream);
        this.kryo=KryoUtils.get();
    }

    @Override
    public <T> T readObject(Class<T> clazz) throws IOException {
        try {
            return kryo.readObjectOrNull(input,clazz);
        }catch(KryoException e){
            throw new IOException(e);
        }
    }

    @Override
    public <T> T readObject(Class<T> clazz, Type type) throws IOException {
        return readObject(clazz);
    }

    @Override
    public boolean readBoolean() throws IOException {
        try {
            return input.readBoolean();
        }catch(KryoException e){
            throw new IOException(e);
        }
    }

    @Override
    public byte readByte() throws IOException {
        try {
            return input.readByte();
        }catch(KryoException e){
            throw new IOException(e);
        }
    }

    @Override
    public byte[] readBytes() throws IOException {
        try {
            int len = input.readInt();
            if (len < 0) {
                return null;
            } else if (len == 0) {
                return new byte[] {};
            } else {
                return input.readBytes(len);
            }
        } catch (KryoException e) {
            throw new IOException(e);
        }
    }

    @Override
    public short readShort() throws IOException {
        try {
            return input.readShort();
        } catch (KryoException e) {
            throw new IOException(e);
        }
    }

    @Override
    public int readInt() throws IOException {
        try {
            return input.readInt();
        } catch (KryoException e) {
            throw new IOException(e);
        }
    }

    @Override
    public long readLong() throws IOException {
        try {
            return input.readLong();
        } catch (KryoException e) {
            throw new IOException(e);
        }
    }

    @Override
    public float readFloat() throws IOException {
        try {
            return input.readFloat();
        } catch (KryoException e) {
            throw new IOException(e);
        }
    }

    @Override
    public double readDouble() throws IOException {
        try {
            return input.readDouble();
        } catch (KryoException e) {
            throw new IOException(e);
        }
    }

    @Override
    public String readUtfString() throws IOException {
        try {
            return input.readString();
        } catch (KryoException e) {
            throw new IOException(e);
        }
    }

    @Override
    public void cleanup() {
        KryoUtils.releaseInput(input);
        KryoUtils.release(kryo);
    }
}
